home *** CD-ROM | disk | FTP | other *** search
- # -*- coding: utf-8 -*-
- #
- # (c) Copyright 2003-2007 Hewlett-Packard Development Company, L.P.
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- #
-
- # Std Lib
- import struct
- import time
- import fnmatch
- import mimetypes
- import array
-
- # Local
- from base.g import *
- from base.codes import *
- from base import device, utils, exif
-
- try:
- import pcardext
- except ImportError:
- if not os.getenv("HPLIP_BUILD"):
- log.error("PCARDEXT could not be loaded. Please check HPLIP installation.")
- sys.exit(1)
-
- # Photocard command codes
- ACK = 0x0100
- NAK = 0x0101
- READ_CMD = 0x0010
- WRITE_CMD = 0x0020
-
- SECTOR_SIZE = 512 # don't change this (TODO: impl. in pcardext)
-
- # Photocard sector cache
- MAX_CACHE = 512 # units = no. sectors
-
- # PhotoCardFile byte cache
- # Used for thumbnails
- INITIAL_PCARDFILE_BUFFER = 20*SECTOR_SIZE
- INCREMENTAL_PCARDFILE_BUFFER = 2*SECTOR_SIZE
-
- class PhotoCardFile:
- # File-like interface
-
- def __init__(self, pc, name=None):
- self.pos = 0
- self.closed = True
- self.file_size = 0
- self.pc = pc
- self.buffer = array.array('c')
-
- if name is not None:
- self.open(name)
-
- self.buffer_size = INITIAL_PCARDFILE_BUFFER
- self.buffer.fromstring(pcardext.read(self.name, 0, self.buffer_size))
-
-
- def open(self, name):
- self.closed = False
- self.name = name
-
- def seek(self, offset, whence=0):
- if whence == 0:
- self.pos = offset
- elif whence == 1:
- self.pos += offset
- elif whence == 2:
- self.pos = self.file_size - offset
- else:
- return
-
-
- def tell(self):
- return self.pos
-
-
- def read(self, size):
- if size > 0:
- if self.pos + size < self.buffer_size:
- data = self.buffer[self.pos : self.pos + size].tostring()
- self.pos += size
- return data
- else:
- # Read some more in from the card to satisfy the request
- while self.pos + size >= self.buffer_size:
- self.buffer.fromstring(pcardext.read(self.name, self.buffer_size, INCREMENTAL_PCARDFILE_BUFFER))
- self.buffer_size += INCREMENTAL_PCARDFILE_BUFFER
- return self.read(size)
-
-
- def close(self):
- self.closed = True
- self.pos = 0
-
-
- class PhotoCard:
-
- def __init__(self, dev_obj=None, device_uri=None, printer_name=None):
-
- if dev_obj is None:
- self.device = device.Device(device_uri, printer_name)
- self.device.open()
- self.close_device = True
- else:
- self.device = dev_obj
- self.close_device = False
-
- self.dir_stack = utils.Stack()
- self.current_dir = []
- self.device_uri = self.device.device_uri
- self.pcard_mounted = False
- self.saved_pwd = []
- self.sector_buffer = {}
- self.sector_buffer_counts = {}
- self.cache_flag = True
- self.write_protect = False
-
- self.callback = None
-
- self.channel_opened = False
-
-
- def START_OPERATION(self, name=''):
- pass
-
- def END_OPERATION(self, name='', flag=True):
- if self.channel_opened and flag:
- self.close_channel()
-
- def set_callback(self, callback):
- self.callback = callback
-
- def _read(self, sector, nsector):
- log.debug("read pcard sector: sector=%d count=%d" % (sector, nsector))
-
- if self.cache_flag:
- for s in range(sector, sector+nsector):
- if s not in self.sector_buffer:
- break
- else:
- buffer = ''
- for s in range(sector, sector+nsector):
- buffer = ''.join([buffer, self.sector_buffer[s]])
- log.debug("Cached sector read sector=%d" % s)
- count = self.sector_buffer_counts[s]
- self.sector_buffer_counts[s] = count+1
-
- if self.callback is not None:
- self.callback()
-
- #log.log_data(buffer)
- return buffer
-
- if self.callback is not None:
- self.callback()
-
- if not self.channel_opened:
- self.open_channel()
-
- log.debug("Normal sector read sector=%d count=%d" % (sector, nsector))
- sectors_to_read = range(sector, sector+nsector)
- request = struct.pack('!HH' + 'I'*nsector, READ_CMD, nsector, *sectors_to_read)
- #log.log_data(request)
-
- if self.callback is not None:
- self.callback()
-
- # send out request
- bytes_written = self.device.writePCard(request)
- log.debug("%d bytes written" % bytes_written)
-
- # read return code
- data = self.device.readPCard(2)
- #log.log_data(data)
- code = struct.unpack('!H', data)[0]
-
- log.debug("Return code: %x" % code)
-
- if code == 0x0110:
-
- # read sector count and version
- data = self.device.readPCard(6)
- nsector_read, ver = struct.unpack('!IH', data)
-
- log.debug("code=0x%x, nsector=%d, ver=%d" % (code, nsector_read, ver))
-
- buffer, data_read, total_to_read = '', 0, nsector * SECTOR_SIZE
-
- while (data_read < total_to_read):
- data = self.device.readPCard(total_to_read)
-
- data_read += len(data)
- buffer = ''.join([buffer, data])
-
- if self.callback is not None:
- self.callback()
-
- if self.cache_flag:
- i = 0
-
- for s in range(sector, sector + nsector_read):
- self.sector_buffer[s] = buffer[i : i+SECTOR_SIZE]
- #log.debug("Sector %d data=\n%s" % (s, repr(self.sector_buffer[s])))
- count = self.sector_buffer_counts.get(s, 0)
- self.sector_buffer_counts[s] = count+1
- i += SECTOR_SIZE
-
- if self.callback is not None:
- self.callback()
-
- self._check_cache(nsector)
-
- #log.log_data(buffer)
- return buffer
- else:
- log.error("Error code: %d" % code)
- return ''
-
- def _write(self, sector, nsector, buffer):
-
- #log.debug("write pcard sector: sector=%d count=%d len=%d data=\n%s" % (sector, nsector, len(buffer), repr(buffer)))
- log.debug("write pcard sector: sector=%d count=%d len=%d" % (sector, nsector, len(buffer)))
-
- if not self.channel_opened:
- self.open_channel()
-
-
- sectors_to_write = range(sector, sector+nsector)
- request = struct.pack('!HHH' + 'I'*nsector, WRITE_CMD, nsector, 0, *sectors_to_write)
- request = ''.join([request, buffer])
-
- if self.callback is not None:
- self.callback()
-
- self.device.writePCard(request)
- data = self.device.readPCard(2)
-
- if self.callback is not None:
- self.callback()
-
- code = struct.unpack('!H', data)[0]
-
- if code != NAK:
- if self.cache_flag:
- i = 0
- for s in range(sector, sector+nsector):
- log.debug("Caching sector %d" % sector)
- self.sector_buffer[s] = buffer[i:i+SECTOR_SIZE]
- self.sector_buffer_counts[s] = 1
- i += SECTOR_SIZE
-
- if self.callback is not None:
- self.callback()
-
- self._check_cache(nsector)
-
- return 0
-
- else:
- if self.cache_flag:
- for s in range(sector, sector+nsector):
- try:
- del self.sector_buffer[s]
- del self.sector_buffer_counts[s]
- except KeyError:
- pass
-
- log.error("Photo card write failed (Card may be write protected)")
- self.close_channel()
- return 1
-
-
- def _check_cache(self, nsector):
- if len(self.sector_buffer) > MAX_CACHE:
- # simple minded: scan for first nsector sectors that has count of 1 and throw it away
- t, n = self.sector_buffer.keys()[:], 0
- for s in t:
- if self.sector_buffer_counts[s] == 1:
- del self.sector_buffer[s]
- del self.sector_buffer_counts[s]
- n += 1
- if n >= nsector:
- break
- if self.callback is not None:
- self.callback()
-
-
-
- def cache_info(self):
- return self.sector_buffer_counts
-
- def cache_check(self, sector):
- return self.sector_buffer_counts.get(sector, 0)
-
- def cache_control(self, control):
- self.cache_flag = control
-
- if not self.cache_flag:
- self.cache_reset()
-
- def cache_state(self):
- return self.cache_flag
-
- def cache_reset(self):
- self.sector_buffer.clear()
- self.sector_buffer_counts.clear()
-
- def df(self):
- df = 0
- self.START_OPERATION('df')
- try:
- df = pcardext.df()
- finally:
- self.END_OPERATION('df')
- return df
-
- def ls(self, force_read=True, glob_list='*', openclose=True):
- if not glob_list:
- glob_list = '*'
- if force_read:
- self.START_OPERATION('ls')
- try:
- self.current_dir = pcardext.ls()
- finally:
- self.END_OPERATION('ls', openclose)
-
- self.current_dir = [(n.lower(),a,s) for (n,a,s) in self.current_dir]
-
- if glob_list == '*':
- return self.current_dir
-
- return [fnmatch.filter(self.current_dir, x) for x in glob_list.strip().lower().split()][0]
-
- def size(self, name):
- for f in self.current_dir:
- if f == name:
- return self.current_dir[f][2]
- return 0
-
- def current_files(self):
- return [x for x in self.current_dir if x[1] != 'd']
-
- def current_directories(self):
- return [x for x in self.current_dir if x[1] == 'd']
-
- def match_files(self, glob_list):
- if len(glob_list) > 0:
- current_files = [x[0] for x in self.current_files()]
- return [fnmatch.filter(current_files, x) for x in glob_list.strip().lower().split()][0]
- return []
-
- def match_dirs(self, glob_list):
- if len(glob_list) > 0:
- current_dirs = [x[0] for x in self.current_directories()]
- return [fnmatch.filter(current_dirs, x) for x in glob_list.strip().lower().split()][0]
- return []
-
- def classify_file(self, filename):
- t = mimetypes.guess_type(filename)[0]
- if t is None:
- return 'unknown/unknown'
- return t
-
- # copy a single file fom pwd to lpwd
- def cp(self, name, local_file, openclose=True):
- self.START_OPERATION('cp')
- total = 0
- try:
- f = file(local_file, 'w');
- total = pcardext.cp(name, f.fileno())
- f.close()
- finally:
- self.END_OPERATION('cp', openclose)
- return total
-
- # cp multiple files in the current working directory
- def cp_multiple(self, filelist, remove_after_copy, cp_status_callback=None, rm_status_callback=None):
- delta, total = 0, 0
- self.START_OPERATION('cp_multiple')
- t1 = time.time()
- try:
- for f in filelist:
-
- size = self.cp(f, f, False)
-
- if cp_status_callback:
- cp_status_callback(os.path.join(self.pwd(), f), os.path.join(os.getcwd(), f), size)
-
- total += size
-
-
- if remove_after_copy:
- pcardext.rm(f)
-
- t2 = time.time()
- delta = t2-t1
- finally:
- if remove_after_copy:
- self.ls(True, '*', False)
- self.END_OPERATION('cp_multiple')
- return (total, delta)
-
- # cp multiple files with paths
- def cp_list(self, filelist, remove_after_copy, cp_status_callback=None, rm_status_callback=None):
- self.save_wd()
- delta, total = 0, 0
- self.START_OPERATION('cp_list')
- t1 = time.time()
- try:
- for f in filelist:
-
- path_list = f.split('/')[:-1]
- filename = f.split('/')[-1]
-
- for p in path_list:
- self.cd(p, False)
-
- size = self.cp(filename, filename, False)
-
- if cp_status_callback is not None:
- cp_status_callback(f, os.path.join(os.getcwd(), filename), size)
-
- total += size
-
- if remove_after_copy:
- pcardext.rm(filename)
-
- if rm_status_callback is not None:
- rm_status_callback(f)
-
- self.cd('/', False)
-
- t2 = time.time()
- delta = t2-t1
- finally:
- #if remove_after_copy:
- # self.ls( True, '*', False )
- self.restore_wd()
- self.END_OPERATION('cp_list')
- return (total, delta)
-
-
-
- def cp_fd(self, name, fd):
- total = 0
- self.START_OPERATION('cp_fd')
- try:
- total = pcardext.cp(name, fd)
- finally:
- self.END_OPERATION('cp_fd')
- return total
-
-
- def unload(self, unload_list, cp_status_callback=None, rm_status_callback=None, dont_remove=False):
- was_cancelled = False
- self.save_wd()
- self.START_OPERATION('unload')
- total = 0
- t1 = time.time()
-
- for f in unload_list:
- if not was_cancelled:
- name, size, typ, subtyp = f
-
- p = name.split('/')
- dirs = p[:-1]
- filename = p[-1]
- self.cd('/', False)
-
- if cp_status_callback is not None:
- if cp_status_callback(os.path.join(self.pwd(), filename),
- os.path.join(os.getcwd(), filename), 0):
- was_cancelled = True
- break
-
- if len(dirs) > 0:
- for d in dirs:
- self.cd(d, False)
-
- if os.path.exists(os.path.join(os.getcwd(), filename)):
- i = 2
-
- while True:
- if not os.path.exists(os.path.join(os.getcwd(), filename + " (%d)" % i)):
- break
-
- i += 1
-
- total += self.cp(filename, filename + " (%d)" % i, False)
-
- else:
- total += self.cp(filename, filename, False)
-
- if cp_status_callback is not None:
- if cp_status_callback(os.path.join(self.pwd(), filename),
- os.path.join(os.getcwd(), filename), size):
- was_cancelled = True
- break
-
- if not dont_remove:
- if rm_status_callback is not None:
- rm_status_callback(os.path.join(self.pwd(), filename))
-
- self.rm(filename, False, False)
-
-
- t2 = time.time()
- self.restore_wd(False)
- self.ls(True, '*', False)
- self.END_OPERATION('unload')
-
- return total, (t2-t1), was_cancelled
-
-
- def get_unload_list(self):
- tree = self.tree()
- return self.__build_unload_list(tree)
-
-
- def __build_unload_list(self, tree, path=None, out=None):
- if path is None:
- out = []
- path = utils.Stack()
- for d in tree:
- if type(tree[d]) == type({}):
- path.push(d)
- self.__build_unload_list(tree[d], path, out)
- path.pop()
- else:
- typ, subtyp = self.classify_file(d).split('/')
- if typ in ['image', 'audio', 'video']:
- p = path.as_list()
- name = '/'.join(['/'.join(p), d])
- out.append((name, tree[d], typ, subtyp))
-
- return out
-
-
- def info(self):
- return pcardext.info()
-
-
- def cd(self, dirs, openclose=True):
- self.START_OPERATION('cd')
- try:
- stat = pcardext.cd(dirs)
- if stat:
- if dirs == '/':
- self.dir_stack.clear()
-
- else:
- dirs = dirs.split('/')
- for d in dirs:
- self.dir_stack.push(d)
-
- self.ls(True, '*', False)
-
- finally:
- self.END_OPERATION('cd', openclose)
-
-
- def cdup(self, openclose=True):
- if len(self.dir_stack.as_list()) == 0:
- return self.cd('/', openclose)
-
- self.dir_stack.pop()
- self.START_OPERATION('cdup')
- try:
- pcardext.cd('/')
-
- for d in self.dir_stack.as_list():
- pcardext.cd(d)
-
- self.ls(True, '*', False)
- finally:
- self.END_OPERATION('cdup', openclose)
-
- def rm(self, name, refresh_dir=True, openclose=True):
- self.START_OPERATION()
- try:
- r = pcardext.rm(name)
-
- if refresh_dir:
- self.ls(True, '*', False)
- finally:
- self.END_OPERATION(openclose)
- return r
-
- def mount(self):
- log.debug("Mounting photocard...")
- self.START_OPERATION('mount')
- try:
- stat = pcardext.mount(self._read, self._write)
- disk_info = pcardext.info()
- self.write_protect = disk_info[8]
- log.debug("stat=%d" % stat)
-
- if stat == 0:
- if self.write_protect:
- # if write_protect is True,
- # card write NAK'd and channel was
- # closed. We have to reopen here.
- self.open_channel()
-
- self.pcard_mounted = True
- pcardext.cd('/')
-
- self.ls(True, '*', False)
-
- else:
- self.pcard_mounted = False
- raise Error(ERROR_DEVICE_DOES_NOT_SUPPORT_OPERATION)
- finally:
- if self.pcard_mounted:
- self.END_OPERATION('mount')
-
-
-
- def pwd(self):
- return '/' + '/'.join(self.dir_stack.as_list())
-
-
- def save_wd(self):
- self.saved_pwd = self.dir_stack.as_list()[:]
-
- def restore_wd(self, openclose=True):
- self.cd('/', openclose)
- for d in self.saved_pwd:
- self.cd(d, openclose)
-
-
- def tree(self):
- self.START_OPERATION('tree')
- dir_tree = {}
- try:
- self.save_wd()
- dir_tree = self.__tree()
- self.restore_wd(False)
- finally:
- self.END_OPERATION('tree')
- return dir_tree
-
- def __tree(self, __d=None):
- if __d is None:
- __d = {}
- pcardext.cd('/')
-
- for f in pcardext.ls(): # True, '*', False ):
- fname = f[0].lower()
-
- if self.callback is not None:
- self.callback()
-
- if fname not in ('.', '..'):
- if f[1] == 'd':
- self.cd(fname, False)
- __d[fname] = {}
- __d[fname] = self.__tree(__d[fname])
- self.cdup(False)
-
- else:
- __d[fname] = f[2]
-
- return __d
-
-
- def get_exif(self, name):
- exif_info = {}
- self.START_OPERATION('get_exif')
- pcf = None
- try:
- pcf = PhotoCardFile(self, name)
- exif_info = exif.process_file(pcf)
- finally:
- if pcf is not None:
- pcf.close()
- self.END_OPERATION('get_exif')
- return exif_info
-
-
- def get_exif_path(self, name):
- exif_info = {}
- self.START_OPERATION('get_exif_path')
- self.save_wd()
- try:
- path_list = name.split('/')[:-1]
- filename = name.split('/')[-1]
-
- for p in path_list:
- self.cd(p, False)
-
- pcf = PhotoCardFile(self, filename)
- exif_info = exif.process_file(pcf)
-
- finally:
- self.restore_wd(False)
- pcf.close()
- self.END_OPERATION('get_exif_path')
- return exif_info
-
-
-
- def sector(self, sector):
- self.START_OPERATION('sector')
- try:
- data = self._read(sector, 1)
- finally:
- self.END_OPERATION('sector')
- return data
-
- def umount(self):
- pcardext.umount()
- self.pcard_mounted = False
-
- def open_channel(self):
- self.channel_opened = True
- self.device.openPCard()
-
- def close_channel(self):
- self.channel_opened = False
- self.device.closePCard()
-
-
-
-
-
-
-